<template>
  <div>
    <div v-for="(comps, key) in components">
      <ElDivider border-style="dashed">{{ displayNames[key] }}</ElDivider>
      <div class="comps">
        <VueDraggable
          v-model="components[key]"
          :sort="false"
          :group="{ name: 'components', pull: 'clone', put: false }"
          :clone="(comp) => createComponent(comp, key, true)"
          tag="ul"
        >
          <li
            v-for="item in comps"
            :key="item.type"
            @click="createComponent(item, key)"
          >
            <i class="iconfont" :class="item.icon"></i>
            <span> {{ item.displayName }}</span>
          </li>
        </VueDraggable>
      </div>
    </div>
  </div>
</template>

<script setup>
import { reactive, ref } from "vue";
import {
  displayNames,
  codeBuilderComponentsMap,
} from "@/configs/codeBuilderCompMap";
import { useCodeBuilderState } from "@/store/codeBuilder/codeBuilder";
import { VueDraggable } from "vue-draggable-plus";
const codeBuilderState = useCodeBuilderState();
const componentDefaultConfig = codeBuilderState.componentDefaultConfig;
const components = ref({});
for (const key in codeBuilderComponentsMap) {
  components.value[key] = Object.entries(codeBuilderComponentsMap[key]).map(
    ([compName, option]) => {
      const { icon, displayName } = option();
      return {
        icon,
        displayName,
        type: compName,
      };
    }
  );
}
let fieldId = 1;
// 构建组件
function genComponent(comp, kind) {
  const options = codeBuilderComponentsMap[kind][comp.type]();
  const component = {
    ...options,
    state: {
      value: comp.defaultValue ?? null,
    }, // 组件属性状态
    kind, // 组件所属类别
  };

  if (component.kind === "form") {
    // 生成字段
    component.state.label = component.state.prop = `field${fieldId++}`;
  }
  if (componentDefaultConfig[comp.type]) {
    const state = componentDefaultConfig[comp.type]();
    Object.assign(component.state, state);
  }
  return component;
}

/**
 * 创建组件
 * @param comp 组件
 * @param kind 组件所属
 * @param isDrag 是否拖拽
 */
function createComponent(comp, kind, isDrag = false) {
  const newComp = genComponent(comp, kind);
  if (isDrag) {
    return codeBuilderState.normalizeComp(newComp);
  } else {
    codeBuilderState.addComponent(newComp);
  }
}
</script>

<style scoped>
.comps ul {
  padding: 5px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  align-items: center;
  user-select: none;
}
.comps ul li {
  padding: 5px;
  cursor: pointer;
  border: 1px solid var(--border-color);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--text-secondary);
  border-radius: 5px;
  transition: border-color 0.3s ease, color 0.3s ease;
}
ul li:hover {
  border-color: var(--el-color-primary);
  color: var(--el-color-primary);
}
ul li .iconfont {
  margin-right: 5px;
  font-size: 1.15rem;
}
</style>
